package ua.exchangeratesukraine.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Locale;

import ua.exchangeratesukraine.R;
import ua.exchangeratesukraine.model.CurrencyModel;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
import android.view.View;

public class Util {

	private final static String	LOG_TAG			= "Util";
	private static String		month_easter	= "";
	private static String		day_easter		= "";
	private static String		month_trinity	= "";
	private static String		day_trinity		= "";

	private static int			sYear			= 0;
	private static int			sMonth			= 0;
	private static int			sDayOfMonth		= 0;
	private static int			setMonth		= 0;

	private static int			currentYear		= 0;
	private static int			currentMonth	= 0;
	private static int			currentDay		= 0;

	static {
		currentYear = Calendar.getInstance().get(Calendar.YEAR);
		currentMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;
		currentDay = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
	}

	public static void calcHoliday(int year) {
		int a = (19 * (year % 19) + 15) % 30;
		int b = (2 * (year % 4) + 4 * (year % 7) + 6 * a + 6) % 7;

		int oldDate = (a + b) > 9 ? (a + b - 9) : (22 + a + b);

		int newDate;
		String newMonth = "";

		int newDateTrinity = 0;
		String newMonthTrinity = "";
		// 4 - april; 5 - may ; 6 - june
		if ((a + b) > 9) { // april
			newDate = oldDate + 13 > 30 ? oldDate + 13 - 30 : oldDate + 13;
			newMonth = oldDate + 13 > 30 ? "5" : "4";

			newDateTrinity = ((oldDate + 13) + 49 > 61) ? ((oldDate + 13) + 19 - 31) : (oldDate + 13) + 19;

			newMonthTrinity = (((oldDate + 13) + 49) > 60) ? "6" : "5";

		} else { // march
			newDate = oldDate + 13 > 31 ? oldDate + 13 - 31 : oldDate + 13;
			newMonth = oldDate + 13 > 31 ? "4" : "3";

			newDateTrinity = ((oldDate + 13) + 49 > 61) ? ((oldDate + 13) + 19 - 31) : (oldDate + 13) + 19;
			newMonthTrinity = (((oldDate + 13) + 49) > 92) ? "6" : "5";
		}

		month_easter = newMonth;
		day_easter = String.valueOf(newDate);
		month_trinity = newMonthTrinity;
		day_trinity = String.valueOf(newDateTrinity);

	}

	public static String date = "";
	
	public static void setLastWorkDate(String date, int dayNumber) {
		long dateMills = stringToLong(date); // current date in millises
		long dayNumberMills = dayToMills(dayNumber); //  time offset in millises  
		long lastWorkDateMills = dateMills - dayNumberMills;
		Util.date = longToString(lastWorkDateMills);
	}
	
	public static void checkHoliday(ArrayList<String> holidayMonthArray, ArrayList<String> holidayDayArray,
			String date) {

		Util.date = date;
		initTime(Util.date);

		// check holidays
		int j = 0;
		for (String holidayMonth : holidayMonthArray) {
			if (sMonth == Integer.valueOf(holidayMonth) && sDayOfMonth == Integer.valueOf(holidayDayArray.get(j))) {
				setLastWorkDate(date, 1); // init Util.date
				initTime(Util.date);
				
				int k = 0;
				for (String holidayMonth2 : holidayMonthArray) {
					if (sMonth == Integer.valueOf(holidayMonth2) && sDayOfMonth == Integer.valueOf(holidayDayArray.get(k))) {
						setLastWorkDate(Util.date, 1); // init Util.date
					}
					k++;
				}
			}
			j++;
		}
	}
	public static void checkDayOff(ArrayList<String> holidayMonthArray, ArrayList<String> holidayDayArray,
			String date) {

		Util.date = date;
		initTime(date);
		Util.calcHoliday(sYear);

		holidayMonthArray.add(month_easter);
		holidayMonthArray.add(month_trinity);
		holidayDayArray.add(day_easter);
		holidayDayArray.add(day_trinity);

		Calendar c = Calendar.getInstance(Locale.getDefault());
		c.set(sYear, setMonth, sDayOfMonth);

		String dayOfWeek = c.getDisplayName(Calendar.DAY_OF_WEEK, 1, java.util.Locale.UK);

		// check off-day
		if (dayOfWeek.equals(Constants.SATURDAY)) {
			setLastWorkDate(Util.date, 1);
			checkHoliday(holidayMonthArray, holidayDayArray, Util.date);
			return;
		}
		if (dayOfWeek.equals(Constants.SUNDAY)) {
			setLastWorkDate(Util.date, 2);
			checkHoliday(holidayMonthArray, holidayDayArray, Util.date);
			return;
		}

		// check off-day transfer (monday after sunday or saturday)
		int tempDaySaturday = sDayOfMonth - 2;
		int tempDaySunday = sDayOfMonth - 1;
		int i = 0;
		if (dayOfWeek.equals(Constants.MONDAY)) {
			for (String holidayMonth : holidayMonthArray) {
				if (   sMonth == Integer.valueOf(holidayMonth)
					&& (tempDaySunday == Integer.valueOf(holidayDayArray.get(i)) 
					|| tempDaySaturday == Integer.valueOf(holidayDayArray.get(i)))) {
					setLastWorkDate(Util.date, 3);
					checkHoliday(holidayMonthArray, holidayDayArray, Util.date);
					return;
				}
				i++;
			}
		}
	}

	public static void initTime(String date) {
		try {
			sYear = Integer.valueOf(date.substring(0, 4));
			sMonth = Integer.valueOf(date.substring(5, 7));
			sDayOfMonth = Integer.valueOf(date.substring(8));
			setMonth = sMonth - 1;
		} catch (Exception e) {
			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
			Calendar cal = Calendar.getInstance();
			initTime( dateFormat.format(cal.getTime()) );			 
			e.printStackTrace();
		}
	}

	public static boolean isTimeFuture(String date) {
		initTime(date);
		if (currentYear < sYear || (currentYear <= sYear && currentMonth < sMonth)
				|| (currentYear <= sYear && currentMonth <= sMonth && currentDay < sDayOfMonth)) {
			return true;
		}
		return false;
	}

	public static boolean isNetworkAvailable(Context context) {
		ConnectivityManager connectivityManager = (ConnectivityManager) context
				.getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
		return ((netInfo != null && netInfo.isConnectedOrConnecting()) ? true : false);
	}
	
	public static String longToString(long date) {
		return (new java.sql.Date(date)).toString();
	}

	public static long stringToLong(String inputDate) {
		long mills = 0;
		try {
			mills = ((Date) (new SimpleDateFormat("yyyy-MM-dd")).parse(inputDate)).getTime();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return mills;
	}
	
	public static long getCurrentTime() {
		return (new Date().getTime());
	}

	public static byte[] getByteArrayFromObject(Object object) {

		if (object == null) {
			return null;
		}
		
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oos = null;
		byte[] result = null;
		try {
			oos = new ObjectOutputStream(baos);
			oos.writeObject(object);
			result = baos.toByteArray();
			oos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}

	public static Object getObjectFromByteArray(byte [] array) {
		
		ByteArrayInputStream bais = new ByteArrayInputStream(array);
		ObjectInputStream ois = null;
		Object object = null;
		try {
			ois = new ObjectInputStream(bais);
			try {
				object = ois.readObject();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
			ois.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return object;
	}
	
	private static int touchUnitCount = 0;
	private static int touchBuyCount = 0;
	private static int touchSaleCount = 0;
	private static int touchAbsBuyCount = 0;
	private static int touchAbsSaleCount = 0;
	private static int touchRelBuyCount = 0;
	private static int touchRelSaleCount = 0;

	public static ArrayList<CurrencyModel> sortBanks(final View view, 
								ArrayList<CurrencyModel> currencyModelArray, boolean isRequest) {

		if (view == null || currencyModelArray.size() <= 1 )
			return currencyModelArray;
		
		if (isRequest) {
			touchUnitCount = 0;
			touchBuyCount = 0;
			touchSaleCount = 0;
			touchAbsBuyCount = 0;
			touchAbsSaleCount = 0;
			touchRelBuyCount = 0;
			touchRelSaleCount = 0;
		}
		switch (view.getId()) {
			case R.id.tvNameCurrencyUnit:
				touchUnitCount++;
				break;
			case R.id.tvNameRateBuy:
				touchBuyCount++;
				break;
			case R.id.tvNameRateSale:
				touchSaleCount++;
				break;
			case R.id.tvNameChangeAbsBuy:
				touchAbsBuyCount++;
				break;
			case R.id.tvNameChangeAbsSale:
				touchAbsSaleCount++;
				break;
			case R.id.tvNameChangeRelBuy:
				touchRelBuyCount++;
				break;
			case R.id.tvNameChangeRelSale:
				touchRelSaleCount++;
				break;
			default:
				break;
		}
		Collections.sort(currencyModelArray, new Comparator<CurrencyModel>() {
			public int compare(CurrencyModel s1, CurrencyModel s2) {
				switch (view.getId()) {
					case R.id.tvNameCurrencyUnit:
						if (touchUnitCount % 2 == 0)
							return s2.getName().compareTo(s1.getName());
						else
							return s1.getName().compareTo(s2.getName());
					case R.id.tvNameRateBuy:
						if (touchBuyCount % 2 == 0)
							return (Double.valueOf(s2.getBuy()).compareTo(Double.valueOf(s1.getBuy())));
						else
							return (Double.valueOf(s1.getBuy()).compareTo(Double.valueOf(s2.getBuy())));
					case R.id.tvNameRateSale:
						if (touchSaleCount % 2 == 0)
							return (Double.valueOf(s2.getSale()).compareTo(Double.valueOf(s1.getSale())));
						else
							return (Double.valueOf(s1.getSale()).compareTo(Double.valueOf(s2.getSale())));
					case R.id.tvNameChangeAbsBuy:
						if (touchAbsBuyCount % 2 == 0)
							return Double.valueOf(s2.getBuyChangeAbs()).compareTo(
									Double.valueOf(s1.getBuyChangeAbs()));
						else
							return Double.valueOf(s1.getBuyChangeAbs()).compareTo(
									Double.valueOf(s2.getBuyChangeAbs()));
					case R.id.tvNameChangeAbsSale:
						if (touchAbsSaleCount % 2 == 0)
							return Double.valueOf(s2.getSaleChangeAbs()).compareTo(
									Double.valueOf(s1.getSaleChangeAbs()));
						else
							return Double.valueOf(s1.getSaleChangeAbs()).compareTo(
									Double.valueOf(s2.getSaleChangeAbs()));
					case R.id.tvNameChangeRelBuy:
						if (touchRelBuyCount % 2 == 0)
							return Double.valueOf(s2.getBuyChangeRel()).compareTo(
									Double.valueOf(s1.getBuyChangeRel()));
						else
							return Double.valueOf(s1.getBuyChangeRel()).compareTo(
									Double.valueOf(s2.getBuyChangeRel()));
					case R.id.tvNameChangeRelSale:
						if (touchRelSaleCount % 2 == 0)
							return Double.valueOf(s2.getSaleChangeRel()).compareTo(
									Double.valueOf(s1.getSaleChangeRel()));
						else
							return Double.valueOf(s1.getSaleChangeRel()).compareTo(
									Double.valueOf(s2.getSaleChangeRel()));
					default:
						break;
				}
				return 0;
			}
		});
	return currencyModelArray;
	}
		
	private static int touchUnitCnt = 0;
	private static int touchChangeCount = 0;
	private static int touchAbsCount = 0;
	private static int touchRelCount = 0;

	
	public static ArrayList<CurrencyModel> sortNBU(final View view, 
							ArrayList<CurrencyModel> currencyModelArray, boolean isRequest) {
		
		if (view == null || currencyModelArray.size() <= 1 )
			return currencyModelArray;
		
		if (isRequest) {
			touchUnitCnt = 0;
			touchChangeCount = 0;
			touchAbsCount = 0;
			touchRelCount = 0;
		}
		switch (view.getId()) {
		case R.id.tvNameCurrencyUnit: 	touchUnitCnt++; 		break;
		case R.id.tvRate:  				touchChangeCount++;	 	break;
		case R.id.tvNameChangeAbsRate:  touchAbsCount++;		break;
		case R.id.tvNameChangeRelRate:	touchRelCount++;		break;
		default:												break;
		}
		if (Locale.getDefault().toString().equals("uk_UA")) {
			for (CurrencyModel currencyModel : currencyModelArray) {
				char[] name = currencyModel.getName().toCharArray();
				if (name[0] == Constants.SYMBOL_UKR_E ){
					name[0] = Constants.SYMBOL_RUS_E;
					currencyModel.setName(String.valueOf(name));
				}
				if (name[0] == Constants.SYMBOL_UKR_I ){
					name[0] = Constants.SYMBOL_RUS_I;
					currencyModel.setName(String.valueOf(name));
				}
			}
		}
		Collections.sort(currencyModelArray, new Comparator<CurrencyModel>() {
			public int compare(CurrencyModel s1, CurrencyModel s2) {
				switch (view.getId()) {
					case R.id.tvNameCurrencyUnit:
						if(touchUnitCnt % 2 == 0)   return s2.getName().compareTo(s1.getName());
						else 					   	  return s1.getName().compareTo(s2.getName()); 
					case R.id.tvRate:
						if(touchChangeCount % 2 == 0) return (Double.valueOf(s2.getRate()).compareTo(
															  Double.valueOf(s1.getRate()))); 
						else 						  return (Double.valueOf(s1.getRate()).compareTo
								  							 (Double.valueOf(s2.getRate()))); 
					case R.id.tvNameChangeAbsRate:
						if(touchAbsCount % 2 == 0) 	  return  Double.valueOf(s2.getChangeAbs()).compareTo
									 							 (Double.valueOf(s1.getChangeAbs()));
						else 						  return  Double.valueOf(s1.getChangeAbs()).compareTo
	 														 (Double.valueOf(s2.getChangeAbs()));
					case R.id.tvNameChangeRelRate:
						if(touchRelCount % 2 == 0)    return  Double.valueOf(s2.getChangeRel()).compareTo
														 	 (Double.valueOf(s1.getChangeRel()));
						else 						  return  Double.valueOf(s1.getChangeRel()).compareTo
								 							 (Double.valueOf(s2.getChangeRel()));
					default:break;
				}
				return 0;
			}
		});
		if (Locale.getDefault().toString().equals("uk_UA")) {
			for (CurrencyModel currencyModel : currencyModelArray) {
				char[] name = currencyModel.getName().toCharArray();
				if (name[0] == Constants.SYMBOL_RUS_E ){
					name[0] = Constants.SYMBOL_UKR_E;
					currencyModel.setName(String.valueOf(name));
				}
				if (name[0] == Constants.SYMBOL_RUS_I ){
					name[0] = Constants.SYMBOL_UKR_I;
					currencyModel.setName(String.valueOf(name));
				}
			}
		}
	return currencyModelArray;
	}
	
	public static long dayToMills(int hour){
		return hour * 24 * 60 * 60 * 1000;
	}
	
}